<template>
  <div class="form-wrap">
    <a-spin :spinning="loading">
      <a-form-model ref="form" :model="model" :rules="validatorRules" v-bind="$attrs">
        <a-row :gutter="gutter">
          <a-col v-bind="item.colSpan || computedColSpan" v-for="item in formData" :key="item.name" v-if="!item.hidden">
            <a-form-model-item
              :labelCol="item.labelCol || labelCol"
              :wrapperCol="item.wrapperCol || wrapperCol"
              :prop="item.name"
              :label="item.label"
              v-bind="item.itemExtra"
            >
              <template v-if="item.scopedSlot && $scopedSlots[item.scopedSlot]">
                <slot :name="item.scopedSlot" :model="model" :option="item" />
              </template>
              <template v-else-if="item.tagName">
                <template v-if="inputTypes.includes(item.tagName)">
                  <component :is="item.tagName" v-model.trim="model[item.name]" v-bind="item.props" v-on="item.on" />
                </template>
                <template v-else>
                  <component :is="item.tagName" v-model="model[item.name]" v-bind="item.props" v-on="item.on" />
                </template>
              </template>
            </a-form-model-item>
          </a-col>
        </a-row>
      </a-form-model>
    </a-spin>
  </div>
</template>

<script>
/**
 * options [{
 *  name,
 *  labelCol,
 *  wrapperCol,
 *  label,
 *  type,
 *  tagName,
 *  scopedSlot,
 *  props,
 *  itemExtra
 *  on,
 *  hidden
 * }]
 */

const types = {
  input: 'a-input',
  select: 'a-select',
  dict: 'j-dict-select-tag',
  inputNumber: 'c-input-number',
  textarea: 'a-textarea',
  radio: 'a-radio-group',
  timePicker: 'a-time-picker',
  datePicker: 'a-date-picker',
  monthPicker: 'a-month-picker',
  rangePicker: 'a-range-picker'
}

function omitEmpty(obj) {
  const newObj = { ...obj }
  Object.keys(newObj).forEach(key => {
    if (newObj[key] === null || newObj[key] === undefined) {
      delete newObj[key]
    }
  })
  return newObj
}
export default {
  name: 'CForm',
  props: {
    options: {
      type: Array,
      require: true
    },
    gutter: {
      type: [Number, Array],
      default: 24
    },
    colSpan: {
      type: Object,
      require: false
    },
    labelCol: {
      type: Object,
      require: false
    },
    wrapperCol: {
      type: Object,
      require: false
    },
    model: {
      type: Object,
      require: false
    },
    loading: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      validatorRules: {},
      formData: [],
      inputTypes: ['a-input', 'c-input-number', 'a-input-number', 'a-textarea', 'input', 'textarea']
    }
  },
  methods: {
    submit() {
      this.$refs.form.validate(valid => {
        if (valid) {
          // const values = omitEmpty(this.model)
          const values = this.model
          this.$emit('submit', values)
        }
      })
    },
    validateField(...args) {
      this.$refs.form.validateField(...args)
    },
    validate(...args) {
      this.$refs.form.validate(...args)
    },
    resetFields(...args) {
      this.$refs.form.resetFields(...args)
    },
    clearValidate(...args) {
      this.$refs.form.clearValidate(...args)
    }
  },
  computed: {
    computedColSpan() {
      const defaultColSpan = this.options.length > 10 ? { md: 12, xs: 24 } : { span: 24 }
      return this.colSpan || defaultColSpan
    }
  },
  watch: {
    options: {
      handler(val) {
        const validatorRules = {}
        this.formData = val.map(item => {
          let { name, type, rules, tagName, initialValue, ...rest } = item
          if (rules) {
            validatorRules[name] = rules
          }
          if (types[type] && !tagName) {
            tagName = types[type]
          }
          return {
            ...rest,
            name,
            tagName
          }
        })
        this.validatorRules = validatorRules
      },
      immediate: true
    }
  }
}
</script>

<style lang="less" scoped>
.form-wrap {
  /deep/ .ant-form-inline {
    .ant-form-item {
      display: flex;
      margin-right: 0;

      .ant-form-item-control-wrapper {
        flex: 1 1;
        display: inline-block;
        vertical-align: middle;
      }

      > .ant-form-item-label {
        line-height: 32px;
        padding-right: 8px;
        width: auto;
      }
      .ant-form-item-control {
        height: 32px;
        line-height: 32px;
      }
    }
  }
  /deep/ .ant-calendar-picker {
    width: 100% !important;
  }
}
</style>
